use crate::db;
use crate::error::AppError;
use crate::models as m;
use crate::routes::handler::RouteHandler;
use crate::routes::payload::Payload;
use crate::routes::response::Response;
use crate::schemas as s;
use crate::schemas::base::{FilterFunc, FilterItem, FilterValue, ListResult};
use crate::services;
use crate::{convert_vec, extract_payload};
use async_trait::async_trait;
use rand::Rng;
use crate::common::variables::update_project_base_dir;

pub struct CreateProject;

#[async_trait]
impl RouteHandler for CreateProject {
    async fn handle(&self, payload: Payload) -> Result<Response, AppError> {
        let data = extract_payload!(payload, Payload::CreateProject)?;
        // 初始化项目
        services::project::init_full(&data.base_dir).await?;
        // 插入项目表
        let mut p: m::project::ActiveModel = data.into();
        let random = rand::rng().random_range(1..=10);
        p.random = sea_orm::Set(Some(random));
        let new_project = db::create::one("app", p).await?;
        let new_project: s::project::ListItem = new_project.into();
        Ok(Response::ProjectEffect(s::base::OneEffect {
            effect: new_project,
        }))
    }
}

pub struct QueryProject;

#[async_trait]
impl RouteHandler for QueryProject {
    async fn handle(&self, payload: Payload) -> Result<Response, AppError> {
        let query = extract_payload!(payload, Payload::ListQuery)?;
        let project_list =
            db::read::list::<m::project::Entity, m::project::Model>("app", query).await?;
        let result: Vec<s::project::ListItem> = convert_vec!(project_list.result);
        Ok(Response::ListProject(ListResult {
            total: project_list.total,
            result,
        }))
    }
}

pub struct LoadProject;

#[async_trait]
impl RouteHandler for LoadProject {
    async fn handle(&self, payload: Payload) -> Result<Response, AppError> {
        let params = extract_payload!(payload, Payload::OperateProject)?;
        let filters = vec![FilterItem {
            field: "id".to_string(),
            func: FilterFunc::EQ,
            value: Some(FilterValue::String(params.id.clone().into())),
        }];
        let project = db::read::one::<m::project::Entity>("app", Some(filters)).await?;
        services::project::load_full(&project.base_dir).await?;

        Ok(Response::NullResult(()))
    }
}

pub struct ImportProject;

#[async_trait]
impl RouteHandler for ImportProject {
    async fn handle(&self, payload: Payload) -> Result<Response, AppError> {
        let data = extract_payload!(payload, Payload::CreateProject)?;
        // 校验项目是否完整
        let is_exist = services::project::check_full(&data.base_dir).await?;
        if !is_exist {
            return Err(AppError::Custom("路径下不存在项目配置，或不完整，无法导入！".to_string()))
        }
        // 插入项目表
        let mut p: m::project::ActiveModel = data.into();
        let random = rand::rng().random_range(1..=10);
        p.random = sea_orm::Set(Some(random));
        let new_project = db::create::one("app", p).await?;
        let new_project: s::project::ListItem = new_project.into();

        // 设置项目路径
        update_project_base_dir(new_project.base_dir.clone());
        
        Ok(Response::ProjectEffect(s::base::OneEffect {
            effect: new_project,
        }))
    }
}